# -*- coding: utf-8 -*-

from sqlalchemy import Column
from sqlalchemy import Integer
from sqlalchemy import MetaData
from sqlalchemy import String
from sqlalchemy import DateTime
from sqlalchemy import Table

import json
import datetime

import gitlab
import db


Actions = {
  'merge_request_begin' : {
    'status' : 1
  },
  'jira_check_failed' : {
    'status' : 2
  },
  'podfile_analyze_begin' : {
    'status' : 3
  },
  'podfile_analyze_end' : {
    'status' : 4
  },
  'pod_install_begin' : {
    'status' : 5
  },
  'pod_install_ing' : {
    'status' : 6
  },
  'pod_install_end' : {
    'status' : 7
  },
  'build_begin' : {
    'status' : 8
  },
  'build_ing' : {
    'status' : 9
  },
  'build_fail_end' : {
    'status' : 10
  },
  'build_success_end' : {
    'status' : 11
  },
  'ci_warehouse' : {
    'status' : 12
  }
}


class BuildData(db.Base):
  __tablename__ = 'tb_build_data'

  # v1.0
  id = Column(Integer,primary_key=True,nullable=False,autoincrement=True)
  status = Column(Integer,unique=False, nullable=True)
  git_commit = Column(String(256),unique=False, nullable=True)
  project_id = Column(String(256),unique=False, nullable=True)
  mr_id = Column(String(256),unique=False, nullable=True)
  error_info = Column(String(2048),unique=False, nullable=True)
  denpendency_json = Column(String(8192),unique=False, nullable=True)
  build_url = Column(String(512),unique=False, nullable=True)
  build_number = Column(String(256),unique=False, nullable=True)
  ipa_url = Column(String(1024),unique=False, nullable=True)
  ipa_size = Column(String(128),unique=False, nullable=True)
  qrcode_url = Column(String(512),unique=False, nullable=True)
  gitlab_mr_url = Column(String(512),unique=False, nullable=True)
  jenkins_log_url = Column(String(512),unique=False, nullable=True)
  ci_warehouse_url = Column(String(512),unique=False, nullable=True)
  note_id = Column(String(128),unique=False, nullable=True)
  date = Column(DateTime, default=datetime.datetime.utcnow, nullable=True)

  # v2.0
  # name = Column(String(100),unique=False, nullable=True)
  # favor = Column(String(100),unique=False, nullable=True)
  
  def to_json(self):
    dict = self.__dict__
    if "_sa_instance_state" in dict:
      del dict["_sa_instance_state"]
    return dict


  def __init__(self):
    self.status = 0

  def date_diff(self, begin_date, end_date):
    seconds = (end_date - begin_date).seconds
    if seconds <= 60:
      return "%d 秒" % seconds
    if seconds <= 3600:
      return "%d 分钟" % round(seconds / 60.0)
    if seconds <= 60:
      return "%d 小时" % round(seconds / 3600.0)


  # HTML 格式化 评论内容
  def get_html_comment(self, msg=''):
    pass


  # Markdown 格式化 评论内容
  def get_markdown_comment(self, msg=''):
    # begin_date = datetime.datetime.now()

    ## comment begin
    comment = "| key | value |\n| ---------- | ------------|\n"

    ## + commit
    commit_line = "| %s | %s |\n" % ('git commit', self.git_commit)
    comment = comment + commit_line

    ## + merge request id
    commit_line = "| %s | %s |\n" % ('merge request id', self.mr_id)
    comment = comment + commit_line

    ## Build URL
    commit_line = "| %s | %s |\n" % ('build url', self.build_url)
    comment = comment + commit_line

    ## Jenkins Log
    commit_line = "| %s | %s |\n" % ('jenkins log url', self.jenkins_log_url)
    comment = comment + commit_line

    ## + begin mr task
    if Actions['merge_request_begin']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':large_blue_circle: begin merge request')
      comment = comment + commit_line
      return comment

    ## + jira check failed
    if Actions['jira_check_failed']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':x: jira check failed')
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('error_info', ":bangbang: %s" % self.error_info)
      comment = comment + commit_line
      return comment

    # + begin Podfile dependency analyzing
    if Actions['podfile_analyze_begin']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':large_blue_circle: begin Podfile dependency analyze')
      comment = comment + commit_line
      return comment

    # + end Podfile dependency analyzing
    if Actions['podfile_analyze_end']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':white_check_mark: end Podfile dependency analyze')
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line
      return comment

    # + begin pod install
    if Actions['pod_install_begin']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':large_blue_circle: begin pod install')
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line
      return comment

    ## + pod installing
    if Actions['pod_install_ing']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ":large_blue_circle: pod install %s" % (msg))
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line
      return comment

    ## + pod install end
    if Actions['pod_install_end']['status'] == self.status:
      ### status
      if 0 == cmp(msg, 'ok'):
        commit_line = "| %s | %s |\n" % ('status', ':white_check_mark: pod install success')
        comment = comment + commit_line
      else:
        commit_line = "| %s | %s |\n" % ('status', ':x: pod install failed')
        comment = comment + commit_line

      ### podfile analyze
      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line

      ### error info
      if None != self.error_info:
        commit_line = "| %s | %s |\n" % ('error info', ":bangbang: %s" % self.error_info)
        comment = comment + commit_line
      return comment

    ## + begin build
    if Actions['build_begin']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':large_blue_circle: begin build')
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line
      return comment
  
    ## + building
    if Actions['build_ing']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', msg)
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line
      return comment

    ## build fail end
    if Actions['build_fail_end']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('status', ':x: build failed')
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
      comment = comment + commit_line

      commit_line = "| %s | %s |\n" % ('error info', ":bangbang: %s" % self.error_info)
      comment = comment + commit_line
      return comment

    ## build success end
    ### status
    commit_line = "| %s | %s |\n" % ('status', ':white_check_mark: build success')
    comment = comment + commit_line

    ### Podfile dependency 
    commit_line = "| %s | %s |\n" % ('Podfile dependency analyze result', self.denpendency_json)
    comment = comment + commit_line

    ### IPA URL
    commit_line = "| %s | %s |\n" % ('ipa url', self.ipa_url)
    comment = comment + commit_line

    ### IPA Size
    commit_line = "| %s | %s |\n" % ('ipa size', self.ipa_size)
    comment = comment + commit_line
    
    ### QRCode
    commit_line = "| %s | ![](%s) |\n" % ('qrcode', self.qrcode_url)
    comment = comment + commit_line

    ## others
    ### ci warehouse url
    if Actions['ci_warehouse']['status'] == self.status:
      commit_line = "| %s | %s |\n" % ('ci warehouse url', self.ci_warehouse_url)
      comment = comment + commit_line
    
    return comment


  def get_comment(self, msg=''):
    return self.get_markdown_comment(msg)
    # return self.get_html_comment(msg)


  @classmethod
  def merge_request_begin(self, value, code):
    # if not all([value]):
    #   raise TypeError('must be passed')

    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_build_number = value['build_number']
    arg_build_url = value['build_url']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    if data:
      # print '存在'
      data.status = code
      data.mr_id = arg_mr_id
      data.build_url = arg_build_url
      data.build_number = arg_build_number
      
      if data.build_url.endswith('/'):
        data.jenkins_log_url = "%s%s" %(data.build_url, 'consoleText')
      else:
        data.jenkins_log_url = "%s/%s" %(data.build_url, 'consoleText')
      
      comment = data.get_comment()
      # print "comment = %s" % comment
      gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    else:
      # print '不存在'
      data = BuildData()
      data.status = code
      data.project_id = arg_project_id
      data.mr_id = arg_mr_id
      data.build_url = arg_build_url
      data.build_number = arg_build_number

      if data.build_url.endswith('/'):
        data.jenkins_log_url = "%s%s" %(data.build_url, 'consoleText')
      else:
        data.jenkins_log_url = "%s/%s" %(data.build_url, 'consoleText')
      data.git_commit = arg_git_commit
      
      comment = data.get_comment()
      # print "comment = %s" % comment
      data.note_id = gitlab.add_note(data.project_id, data.mr_id, comment)
      session.add(data)
    session.commit()
    session.close()


  @classmethod
  def jira_check_failed(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_message = value['message']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    data.error_info = arg_message
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def podfile_analyze_begin(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    
    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def podfile_analyze_end(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_result = value['result']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    data.denpendency_json = json.dumps(arg_result)
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def pod_install_begin(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def pod_install_ing(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_pod = value['pod']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    comment = data.get_comment(arg_pod)
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def pod_install_end(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_state = value['state']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    
    if 0 == cmp(arg_state, 'ok'):
      # print '========= pod install success'
      data.error_info = None
    else:
      # print "========= pod install failed: %s" % data.error_info
      data.error_info = value['error_info']
    
    comment = data.get_comment(arg_state)
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def build_begin(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def build_ing(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_target = value['target']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    comment = data.get_comment(arg_target)
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()
    

  @classmethod
  def build_success_end(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_ipa_url = value['ipa_url']
    arg_ipa_size = value['ipa_size']
    arg_qrcode_url = value['qrcode_url']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    data.ipa_url = arg_ipa_url
    data.ipa_size = arg_ipa_size
    data.qrcode_url = arg_qrcode_url
    
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def build_fail_end(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_error_info = value['error_info']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    data.error_info = arg_error_info
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def ci_warehouse(self, value, code):
    arg_git_commit = value['git_commit']
    arg_project_id = value['project_id']
    arg_mr_id = value['mr_id']
    arg_ci_warehouse_url = value['ci_warehouse_url']

    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    data.status = code
    data.ci_warehouse_url = arg_ci_warehouse_url
    comment = data.get_comment()
    gitlab.update_note(data.project_id, data.mr_id, data.note_id, comment)
    session.commit()
    session.close()


  @classmethod
  def get_row(self, arg_project_id, arg_mr_id, arg_git_commit):
    session = db.DBSession()
    data = session.query(BuildData).filter_by(git_commit=arg_git_commit, project_id=arg_project_id, mr_id=arg_mr_id).first()
    session.close()
    return data


# 自动创建 model 对应的 database-table
db.Base.metadata.create_all(db.Engine)


# register <action : BuildData.func>
Actions['merge_request_begin']['func']    = BuildData.merge_request_begin
Actions['jira_check_failed']['func']      = BuildData.jira_check_failed
Actions['podfile_analyze_begin']['func']  = BuildData.podfile_analyze_begin
Actions['podfile_analyze_end']['func']    = BuildData.podfile_analyze_end
Actions['pod_install_begin']['func']      = BuildData.pod_install_begin
Actions['pod_install_ing']['func']        = BuildData.pod_install_ing
Actions['pod_install_end']['func']        = BuildData.pod_install_end
Actions['build_begin']['func']            = BuildData.build_begin
Actions['build_ing']['func']              = BuildData.build_ing
Actions['build_fail_end']['func']         = BuildData.build_fail_end
Actions['build_success_end']['func']      = BuildData.build_success_end
Actions['ci_warehouse']['func']           = BuildData.ci_warehouse


if __name__ == '__main__':
  # 1、add one
  # d = BuildData()
  # d.git_commit = '2222222'
  # d.project_id = '849'
  # d.mr_id = '8767'
  # d.build_number = '99'
  # d.build_url = 'http://www.baidu.com'
  # d.denpendency_json = {'name' : 'xiong', 'age' : 99}
  # d.save()

  # 2、search all
  # for doc in BuildData.objects(git_commit='2222222'):
  #   print doc.denpendency_json

  # 3、search one 
  # d = BuildData.objects(git_commit='2222222').first()
  # print d.denpendency_json

  # 4、update one `serach result`
  # BuildData.objects(git_commit='2222222').update_one(project_id='99999')

  # 5、update all `serach result`
  # BlogPost.objects(id=post.id).update(set__title='Example Post')

  # 6、update `document``
  # post = BlogPost(title="Test", tags=["mongo"])
  # post.save()
  # post.update(push__tags__0=["database", "code"])
  # post.reload()
  pass


# 
# TODO: ..../nicolasserver/alembic/versions/c0c11b3ad56d_v1_0.py 示例
# from alembic import op
# import sqlalchemy as sa
# from sqlalchemy.dialects import mysql
# 
# # revision identifiers, used by Alembic.
# revision = 'c0c11b3ad56d'
# down_revision = None
# branch_labels = None
# depends_on = None
# 
# 
# build_data_helper = sa.Table(
#   'tb_build_data',
#   sa.MetaData(),
# 
#   # 1、old version table column
#   sa.Column('id', sa.Integer, primary_key=True, autoincrement=True),
#   sa.Column('status', sa.Integer, nullable=True),
#   sa.Column('git_commit', sa.String(length=100), nullable=False, unique=True),
#   sa.Column('project_id', sa.String(length=100), nullable=False),
#   sa.Column('mr_id', sa.String(length=100), nullable=False),
#   sa.Column('error_info', sa.String(length=100), nullable=True),
#   sa.Column('denpendency_json', sa.String(length=100), nullable=True),
#   sa.Column('build_url', sa.String(length=100), nullable=True),
#   sa.Column('build_number', sa.String(length=100), nullable=True),
#   sa.Column('ipa_url', sa.String(length=300), nullable=True),
#   sa.Column('ipa_size', sa.String(length=50), nullable=True),
#   sa.Column('qrcode_url', sa.String(length=300), nullable=True),
#   sa.Column('gitlab_mr_url', sa.String(length=300), nullable=True),
#   sa.Column('jenkins_log_url', sa.String(length=300), nullable=True),
#   sa.Column('ci_warehouse_url', sa.String(length=300), nullable=True),
#   sa.Column('note_id', sa.String(length=50), nullable=True),
#   sa.Column('date', sa.DateTime, nullable=True, server_default=sa.func.current_timestamp()),
# 
#   # 2、new version table column
#   # sa.Column('name', sa.String(length=100), nullable=True),
#   # sa.Column('favor', sa.String(length=100), nullable=True)
# )
# 
# 
# def upgrade():
#   # 1、获取数据库链接
#   connection = op.get_bind()
# 
#   # 2、新增的字段
#   op.add_column(
#     'tb_build_data',
#     sa.Column(
#       'name',
#       sa.String(length=100), 
#       nullable=True
#     )
#   )
#   op.add_column(
#     'tb_build_data',
#     sa.Column(
#       'favor',
#       sa.String(length=100), 
#       nullable=True
#     )
#   )
# 
# 
# def downgrade():
#   # 1、
#   connection = op.get_bind()
# 
#   # 2、
#   op.drop_column('tb_build_data', 'name')
#   op.drop_column('tb_build_data', 'favor')
# 